/*
 @Name: 表格插件
 @Author: ray
 @License: MIT
 */
; rayui.define(["layer", "checkbox", 'template', 'page'], function (exports, undef) {
    "use strict";

    var $ = rayui.$,
        win = window,
        $win = $(win),
        doc = document,
        plugName = "table",
        layer = rayui.layer,
        tmpl = rayui.template,
        pagePg = rayui.page,
        chkpg = rayui.checkbox,
        chkAllEvt = "RAYTABLE_ALL",
        chkOneEvt = "RAYTABLE_ONE",
        chkClass = "RAYTABLE-CHK",
        dataCache = {
            tables: {},
            datas: {},
            cols: {},
            jqobjs: {}
        }, tableindex = 0, scrollGap = {}, timer = null;
    $win.resize(function () {
        if (timer != null) clearTimeout(timer);
        timer = setTimeout(function () {
            timer = null;
            for (var t in dataCache.tables) {
                var that = dataCache.tables[t],
                    data = dataCache.datas[that.tableIndex];
                if (!data || data.length === 0) continue;
                DealClass.utils.modifyStyle.call(that);
            }
        }, 20);
    });

    var DealClass = function (table, option) {
        this.elem = table;
        this.tableIndex = tableindex;
        var tempOpt = $.extend(true, {}, DealClass.option);

        //默认不分页
        option.page === undef && (option.page = false);
        //option.page:true
        option.page === true && (option.page = {});

        this.options = $.extend(true, tempOpt, option);

        //行选中样式
        this.options.rowSelectStyle === true && (this.options.rowSelectStyle = "raytable-row-select");

        //初始化
        DealClass.utils.init.call(this);
        return this;
    };
    //可被外部全局配置
    DealClass.option = {
        version: "1.7",
        ajaxData_Code: "ret",
        ajaxData_Msg: "msg",
        ajaxData_Data: "data",
        ajaxData_Count: "count",
        totalRow: false,//总计行
        expandRow: false,//是否支持展开行
        nowrap: true,//是否自动换行，默认不换行
        minHeight: 80,//表格最小高度
        singleSelect: false,//可以选择多行
        checkOnRowClick: false,//点击行时是否选中
        rowSelectStyle: false,//行选中样式
        initOnly: false,//只进行初始化，不请求数据
        localSort: true,//本地排序，默认true，如果不想使用本地排序，请配置成false
        loading: true, //请求数据时，是否显示loading
        cellMinWidth: 60, //所有单元格默认最小宽度
        fieldSerial: "id",
        fieldChecked: "checked",
        fieldDisableCheck: "disableCheck",
        page: $.extend(true, {}, pagePg.options, { btnGroup: false })
    };

    var serialnum = 0;
    function getNum() {
        return serialnum++;
    }

    DealClass.utils = {
        //只运行一次
        initDefault: function () {
            //计算浏览横向滚动条的高度和竖向滚动条的宽度
            var $div = $("<div/>").appendTo($("body"));
            $div.width(100).height(100).css("overflow", "scroll");
            var elem = $div[0];
            scrollGap.width = elem.offsetHeight - elem.clientHeight;
            scrollGap.height = elem.offsetWidth - elem.clientWidth;
            $div.remove();
        },
        init: function () {
            var that = this,
                $t = $(this.elem),
                options = that.options;

            if (options.data && options.data instanceof Array) {
                dataCache.datas[that.tableIndex] = options.data;
                if (options.page) {
                    options.page.count = options.data.length;
                }
            }
            else
                dataCache.datas[that.tableIndex] = [];

            var addExpand = false, cols = dataCache.cols[that.tableIndex] = [];
            options.colsCount = 0;
            options.autoColNums = 0;
            options.minWidth = 0;
            options.autoCols = {};
            //总计
            options.totalRow && (options.totalRow = { field: 0, text: '总计', fields: {} });

            var cellcss = options.cellcss = {}, othercss = {},
                tableHead = (function () {
                    var str = [], totalOpt = options.totalRow;
                    str.push('<table class="raytable-head"><thead>');
                    $(options.cols).each(function (a1, list) {
                        str.push('<tr>');
                        //是否支持展开
                        if (!addExpand && options.expandRow) {
                            addExpand = true;
                            str.push('<th rowspan="' + options.cols.length + '"><span class="raytable-expand"></span></th>');
                            options.minWidth += 37;//左右padding各10px+内容16px+右边框1px
                        }
                        $(list).each(function (a, b) {
                            if (b.fixed === 'left') options.fixedL = true;
                            if (b.fixed === 'right') options.fixedR = true;
                            //待统计的列
                            if (options.totalRow) {
                                b.totalRow && b.field && (totalOpt.fields[b.field] = 0);
                                if (b.totalRowText) {
                                    b.field && (totalOpt.field = b.field);
                                    totalOpt.Text = b.totalRowText;
                                }
                            }
                            //表头和数据共有样式
                            var cellclass = "raytable-cell-" + that.tableIndex + "-" + (b.field ? b.field : getNum());
                            var curCellCss = cellcss[cellclass] = {};
                            //表头特有样式
                            var headclass = "raytable-cell-head-" + that.tableIndex + "-" + (b.field ? b.field : getNum());
                            var curheadCellCss = othercss[headclass] = {};
                            //数据特有样式
                            var curDataCellCss;
                            if (b.field) {
                                var dataclass = "raytable-cell-data-" + that.tableIndex + "-" + (b.field ? b.field : getNum());
                                curDataCellCss = othercss[dataclass] = {};
                            }

                            b.field && cols.push(b);
                            //计算css样式宽度
                            if (!b.hidden && b.field) {
                                if (b.width) {
                                    if (/^\d+$/.test(b.width)) {
                                        curCellCss.width = b.width + "px";
                                        curCellCss["min-width"] = Math.min(options.cellMinWidth, b.width) + "px";
                                        options.minWidth += b.width;
                                    } else if (/^\d+%$/.test(b.width) || b.width === "*") {
                                        options.isPercentWidth = true;
                                        curCellCss.width = b.width;
                                        curCellCss["min-width"] = options.cellMinWidth + "px";
                                        options.minWidth += options.cellMinWidth;
                                    }
                                } else {
                                    var minW = b.minWidth || options.cellMinWidth;
                                    curCellCss["min-width"] = minW + "px";
                                    options.minWidth += minW;
                                    options.autoCols[b.field] = {};
                                    options.autoCols[b.field].minWidth = minW;
                                    options.autoColNums++;
                                }
                                options.colsCount++;
                            }

                            b.align && (curCellCss["text-align"] = b.align);
                            //表头特有样式
                            b.style && (function () {
                                for (var c in b.style)
                                    curheadCellCss[c] = b.style[c];
                            })();
                            //数据特有样式
                            (b.field && b.dataStyle) && (function () {
                                for (var c in b.dataStyle)
                                    curDataCellCss[c] = b.dataStyle[c];
                            })();

                            str.push('<th class="' + cellclass);
                            //是否可拖拽，因为动态隐藏滚动条问题，固定列不支持拖拽宽度，暂时
                            str.push(b.field ? (b.resize ? " raytable-cell-resize" : "") : "");
                            str.push(b.style ? ' ' + headclass : '');
                            str.push(b.hidden ? ' hidden' : '');
                            str.push(b.sort ? ' raytable-sort-th' : '');
                            str.push(options.nowrap ? ' raytable-nowrap' : '');
                            str.push('"');//class结束
                            str.push(b.colspan ? ' colspan=' + b.colspan : '');
                            str.push(b.fixed ? ' fixed=' + b.fixed : '');
                            str.push(b.rowspan ? ' rowspan=' + b.rowspan : '');
                            str.push(b.field ? ' data-field="' + b.field + '"' : '');
                            str.push(b.islink ? ' islink' : '');
                            //str.push(b.sort ? ' data-type="' + (typeof b.sort === "string" ? b.sort : 's') + '"' : '');
                            str.push('>');//th前半开

                            //内容
                            var thContent;
                            if (b.field === 'chk') {
                                //checkbox
                                var title;
                                typeof b.formatter === "function" && (title = b.formatter(null, null, a));
                                thContent = ['<input type="checkbox" class="rayui-checkbox ',
                                    chkClass,
                                    '"',//end class
                                    title ? ' ray-title="' + title + '" ' : '',
                                    ' ray-event="' + chkAllEvt + '" ',
                                    options.singleSelect ? 'disabled' : '',
                                    options.chkSkin ? ' skin="' + options.chkSkin + '"' : "",
                                    '/>'].join('');
                            } else {
                                thContent = b.title === undef ? "" : b.title;
                            }
                            thContent += (b.sort ? '<span class="raytable-sort-span"><i class="raytable-sort raytable-desc"></i><i class="raytable-sort raytable-asc" ></i></span>' : '');

                            str.push(options.nowrap ? '<div class="raytable-nowrap ' + cellclass + ' ' + headclass + '">' + thContent + '</div>' : thContent);
                            str.push('</th>');
                        });
                        str.push("</tr>");
                    });

                    str.push("</thead></table>");

                    return str.join('');
                })(),

                tablebody = '<table class="raytable-body"' + (options.even ? ' ray-even' : '') + '><tbody></tbody></table>',

                tableMain = [
                    '<div class="raytable-box" style="',
                    'min-height:' + options.minHeight + 'px',
                    options.width ? ';width:' + options.width + 'px' : '',
                    '"',//end style
                    options.skin ? ' skin="' + options.skin + '"' : '',
                    '>',
                    '<div class="raytable-head-boxmain">',
                    '<div class="raytable-head-box">',
                    tableHead,
                    '</div>',
                    '</div>',//end raytable-head-boxmain
                    '<div class="raytable-body-boxmain">',
                    '<div class="raytable-body-box" scroll-left=1>',
                    tablebody,
                    '</div>',
                    '</div>',//end raytable-body-boxmain
                    options.totalRow ? '<div class="raytable-total-boxmain"><div class="raytable-total"><table></table></div></div>' : '',
                    '<div class="raytable-fixed raytable-fixed-l"></div>',
                    '<div class="raytable-fixed raytable-fixed-r"></div>',
                    options.page ? '<div class="raytable-page-boxmain" style="text-align:' + options.page.align + '"></div>' : '',
                    //添加补丁
                    (function () {
                        var ss = [], count = options.cols.length;
                        ss.push('<div class="raytable-fixed-amend hidden">');
                        while (count-- > 0)
                            ss.push("<div/>");
                        ss.push("</div>");
                        return ss.join('');
                    })(),
                    '<div class="raytable-style">',
                    '</div>',
                    '<style>',
                    (function () {
                        var ss = [], isempty;
                        //这里只写其他样式，cell共有样式需要在首次初始化数据添加
                        for (var css in othercss) {
                            isempty = true;
                            for (var key in othercss[css]) {
                                if (isempty) {
                                    ss.push("." + css + "{");
                                    isempty = false;
                                }
                                ss.push(key + ":" + othercss[css][key] + ";");
                            }
                            if (!isempty)
                                ss.push("}");
                        }
                        return ss.join('');
                    })(),
                    '</style>',
                    '</div>'
                ].join('');

            $t.after(tableMain);

            //提前设定选择器
            DealClass.utils.jqSelector.call(that);

            //没有写url，认为是本地分页
            if (options.url) {
                DealClass.utils.initHeight.call(that);
                //ajax请求数据
                DealClass.utils.ajaxData.call(that);
            } else {
                DealClass.utils.onRecvData.call(that);
            }
        },
        jqSelector: function () {
            var that = this;

            var jqobjs = dataCache.jqobjs[that.tableIndex] = {};
            jqobjs.tb_box = $(this.elem).next("div.raytable-box");
            //固定表头和列
            jqobjs.tb_fixed = jqobjs.tb_box.find(">div.raytable-fixed");
            jqobjs.tb_fixed_l = jqobjs.tb_box.find(">div.raytable-fixed-l");
            jqobjs.tb_fixed_r = jqobjs.tb_box.find(">div.raytable-fixed-r");
            //thead
            jqobjs.tb_head_boxmain = jqobjs.tb_box.find("div.raytable-head-boxmain");
            jqobjs.tb_head_box = jqobjs.tb_head_boxmain.find("div.raytable-head-box");
            jqobjs.tb_head_fixed_l = jqobjs.tb_head_boxmain.find("div.raytable-fixed-l");
            jqobjs.tb_head_fixed_r = jqobjs.tb_head_boxmain.find("div.raytable-fixed-r");
            jqobjs.tb_head = jqobjs.tb_head_box.find(">table");
            //tbody
            jqobjs.tb_body_boxmain = jqobjs.tb_box.find("div.raytable-body-boxmain");
            jqobjs.tb_body_box = jqobjs.tb_body_boxmain.find("div.raytable-body-box");
            jqobjs.tb_body_fixed_l = jqobjs.tb_body_boxmain.find("div.raytable-fixed-l");
            jqobjs.tb_body_fixed_r = jqobjs.tb_body_boxmain.find("div.raytable-fixed-r");
            jqobjs.tb_body = jqobjs.tb_body_box.find(">table");
            //补丁条
            jqobjs.tb_amend = jqobjs.tb_box.find(">.raytable-fixed-amend");
            //page
            jqobjs.tb_page_box = jqobjs.tb_box.find("div.raytable-page-boxmain");
            jqobjs.tb_head_body = jqobjs.tb_box.find("div.raytable-head-boxmain>div.raytable-head-box>table,div.raytable-body-boxmain>div.raytable-body-box>table");
            //total
            jqobjs.tb_total_boxmain = jqobjs.tb_box.find(">div.raytable-total-boxmain");
            jqobjs.tb_total_box = jqobjs.tb_total_boxmain.find(">div.raytable-total");
            jqobjs.tb_total = jqobjs.tb_total_box.find(">table");
            //css
            jqobjs.div_style = jqobjs.tb_box.find("div.raytable-style");
        },
        onRecvData: function () {
            var that = this,
                options = that.options,
                jqobjs = dataCache.jqobjs[that.tableIndex];

            if (options.initComplete == undef) {
                options.initComplete = true;

                //设置表格法最小宽度
                options.minWidth += options.colsCount;
                jqobjs.tb_head_body.css("min-width", options.minWidth + "px");

                //顺序不能变
                DealClass.utils.renderData.call(that);
                DealClass.utils.initStyle.call(that);
                DealClass.utils.initPage.call(that);
                //表头固定列
                DealClass.utils.initFixedHead.call(that);
                DealClass.utils.addEvents.call(that);
            } else {
                DealClass.utils.renderData.call(that);
                DealClass.utils.initPage.call(that);
            }
            //渲染之前
            typeof options.onBeforeRenderStyle === "function" && options.onBeforeRenderStyle();
            //渲染checkbox
            chkpg.render(jqobjs.tb_box);
            //检查全选
            DealClass.utils.checkIsAll.call(that);
            //设置固定列的高度
            DealClass.utils.setFixedRowHeight.call(that);
            //修改样式
            DealClass.utils.modifyStyle.call(that);
            //所有处理完毕
            typeof options.onComplete === "function" && options.onComplete();
        },
        ajaxData: function () {
            var that = this,
                options = that.options;

            DealClass.utils.showError.call(that, 0);
            if (options.initOnly) {
                options.initOnly = false;
                dataCache.datas[that.tableIndex] = [];
                options.page && (options.page.count = 0);
                DealClass.utils.onRecvData.call(that);
                return;
            }

            DealClass.utils.loading.call(that, 1);
            var data = {};
            if (options.where)
                $.extend(data, options.where);
            if (options.page)
                $.extend(data, { page: options.page.curr, limit: options.page.limit });
            if (options.initSort)
                $.extend(data, options.initSort);

            $.ajax({
                type: options.method || "get",
                url: options.url,
                data: data,
                dataType: "json",
                beforeSend: function (xhr) {
                    if (typeof options.onAjaxBeforeSend === "function" &&
                        options.onAjaxBeforeSend.call(this, xhr) === false) {
                        xhr.abort();
                    }
                },
                success: function (result) {
                    //清除数据
                    DealClass.utils.clearData.call(that);
                    if (typeof options.onAjaxSuccess === "function") {
                        var retData = options.onAjaxSuccess.call(this, result);
                        if (retData == null || typeof retData !== "object") return;
                        result = retData;
                    }
                    //result默认数据格式：ret,msg,count,data
                    var ret = result[options.ajaxData_Code];
                    if (ret !== 0) {
                        DealClass.utils.showError.call(that, (result[options.ajaxData_Msg] || "返回的数据状态异常"));
                    }
                    dataCache.datas[that.tableIndex] = result[options.ajaxData_Data] || [];
                    options.page && (options.page.count = result[options.ajaxData_Count] || 0);
                    ret === 0 && DealClass.utils.onRecvData.call(that);
                },
                error: function (xhr, textStatus, errorThrown) {
                    DealClass.utils.showError.call(that, "请求数据接口异常");
                    //所有处理完毕
                    typeof options.onAjaxError === "function" && options.onAjaxError.call(this, xhr, textStatus, errorThrown);
                },
                complete: function () {
                    DealClass.utils.loading.call(that, 0);
                }
            });
        },
        //type:0关闭1显示
        loading: function (type) {
            var that = this,
                options = that.options;
            if (!options.loading) return;

            var jqobjs = dataCache.jqobjs[that.tableIndex],
                $box = jqobjs.tb_box;

            if (type === 0) {
                $box.removeClass("temp-width-height");
                layer.close(options.layerLoadingIndex);
                return;
            }

            if (type === 1 && options.url) {
                $box.addClass("temp-width-height");
                options.layerLoadingIndex = layer.loading({
                    container: $box,
                    shadow: false
                });
            }
        },
        showError: function (msg) {
            var that = this,
                jqobjs = dataCache.jqobjs[that.tableIndex],
                $diverr = jqobjs.tb_body_box.find("div.raytable-msg");

            if (msg === 0) {
                $diverr.remove();
                return;
            }

            if ($diverr.length === 0)
                $diverr = $('<div class="raytable-msg"/>').appendTo(jqobjs.tb_body_box);

            $diverr.html(msg);
        },
        initStyle: function () {
            var that = this,
                options = that.options,
                jqobjs = dataCache.jqobjs[that.tableIndex];

            //设置共有样式，只初始化时运行一次
            if (options.cellcss) {
                var cellcss = options.cellcss;
                var ss = [], isempty, css;
                ss.push("<style>");
                //这里只写其他样式，cell共有样式需要在首次初始化数据添加
                for (css in cellcss) {
                    isempty = true;
                    for (var key in cellcss[css]) {
                        if (isempty) {
                            ss.push("." + css + "{");
                            isempty = false;
                        }
                        ss.push(key + ":" + cellcss[css][key] + ";");
                    }
                    if (!isempty)
                        ss.push("}");
                }
                ss.push("</style>");
                jqobjs.div_style.html(ss.join(''));
                //设置自动列样式
                isempty = true;
                for (var field in options.autoCols) {
                    isempty = false;
                    css = ".raytable-cell-" + that.tableIndex + "-" + field;
                    var style = DealClass.utils.getCssStyle.call(that, css);
                    options.autoCols[field].style = style;
                }
                isempty && (options.autoCols = undef);
                options.cellcss = undef;
            }
        },
        modifyStyle: function () {
            var that = this;
            DealClass.utils.fullHeight.call(that);
            DealClass.utils.fullWidth.call(that);
            DealClass.utils.modifyFixedHeight.call(that);
        },
        initFixedHead: function () {
            var that = this,
                jqobjs = dataCache.jqobjs[that.tableIndex],
                $tbhead = jqobjs.tb_head,
                tbTop = jqobjs.tb_box.offset().top;

            var htmlL = [], htmlR = [], leftTop = -1000, rightTop = -1000, isInsertL, isInsertR;
            $tbhead.find("tr").each(function () {
                isInsertL = isInsertR = false;
                var $trobj = $(this);
                $(this).find("th").each(function () {
                    var fixed = $(this).attr("fixed");
                    var objClone;
                    if (fixed === 'left') {
                        leftTop === -1000 && (leftTop = $(this).offset().top);
                        if (!isInsertL) { isInsertL = true; htmlL.push('<tr style="height:' + $trobj.height() + 'px">'); }
                        objClone = $(this).clone();
                        htmlL.push(objClone[0].outerHTML);
                    } else if (fixed === 'right') {
                        rightTop === -1000 && (rightTop = $(this).offset().top);
                        if (!isInsertR) { isInsertR = true; htmlR.push('<tr style="height:' + $trobj.height() + 'px">'); }
                        objClone = $(this).clone();
                        htmlR.push(objClone[0].outerHTML);
                    }
                });
                if (isInsertL) htmlL.push("</tr>");
                if (isInsertR) htmlR.push("</tr>");
            });
            if (htmlL.length !== 0) {
                var $headFixedL = $('<div class="raytable-head-box" />');
                $headFixedL.html('<table class="raytable-head"><thead>' + htmlL.join('') + "</thead></table>")
                    .prependTo(jqobjs.tb_fixed_l.css("top", (leftTop - tbTop - 1) + "px"));
            }
            if (htmlR.length !== 0) {
                var $headFixedR = $('<div class="raytable-head-box" />');
                $headFixedR.html('<table class="raytable-head"><thead>' + htmlR.join('') + "</thead></table>")
                    .prependTo(jqobjs.tb_fixed_r.css("top", (rightTop - tbTop - 1) + "px"));
                //右侧宽度滚动条问题
                jqobjs.tb_fixed_r.css("right", scrollGap.width + "px");
            }
            DealClass.utils.setAmendHeight.call(that);
        },
        //设置补丁条高度
        setAmendHeight: function () {

            var that = this,
                jqobjs = dataCache.jqobjs[that.tableIndex],
                $tbhead = jqobjs.tb_head;

            //补丁条的高度
            jqobjs.tb_amend.css("right", scrollGap.width - 49 + "px") //amend宽度50，减去自己的左边框1px
                .find("div").each(function (a) {
                    $(this).height($tbhead.find("tr:eq(" + a + ")").height() - 1);//下边框
                });
        },
        renderData: function () {
            var that = this,
                jqobjs = dataCache.jqobjs[that.tableIndex],
                $tbody = jqobjs.tb_body.find(">tbody"),
                options = that.options,
                totalOpt = options.totalRow,
                data = DealClass.utils.getData.call(that);

            //清除数据
            DealClass.utils.clearData.call(that);

            //设置表头排序图标
            if (options.initSort)
                jqobjs.tb_box.find(".raytable-head th[data-field=" + options.initSort.sortField + "]").attr("sort-type", options.initSort.sortType);

            var $fixedtbodyl = jqobjs.tb_fixed_l.find("div.raytable-body-noscroll table>tbody"),
                $fixedtbodyr = jqobjs.tb_fixed_r.find("div.raytable-body-noscroll table>tbody");
            if (options.fixedL && $fixedtbodyr.length === 0) {
                $('<div class="raytable-body-noscroll" />').html($('<div class="raytable-body-box" />')
                    .html('<table class="raytable-body"' + (options.even ? ' ray-even' : '') + '><tbody></tbody></table>'))
                    .appendTo(jqobjs.tb_fixed_l);
                $fixedtbodyl = jqobjs.tb_fixed_l.find("div.raytable-body-noscroll table>tbody");
            }
            if (options.fixedR && $fixedtbodyr.length === 0) {
                $('<div class="raytable-body-noscroll" />').html($('<div class="raytable-body-box" />')
                    .html('<table class="raytable-body"' + (options.even ? ' ray-even' : '') + '><tbody></tbody></table>'))
                    .appendTo(jqobjs.tb_fixed_r);
                $fixedtbodyr = jqobjs.tb_fixed_r.find("div.raytable-body-noscroll table>tbody");
            }
            if (data.length === 0) {
                DealClass.utils.showError.call(that, "无数据");
                return;
            }

            //合并单元格，instanceof为field数组
            if (options.colspanDefs && options.colspanDefs instanceof Array) {
                var preValue = {}, firstData = data[0], count = data.length;
                if (count > 1) {
                    $.each(options.colspanDefs, function (a, key) {
                        if (firstData.hasOwnProperty(key)) {
                            firstData[key + "rowspan"] = 1;
                            preValue[key] = firstData;
                        }
                    });
                    var i;
                    for (i = 1; i < count; i++) {
                        var model = data[i];
                        for (var key in preValue) {
                            if (model[key] === preValue[key][key]) {
                                preValue[key][key + "rowspan"]++;
                                model[key + "rowspan"] = -1;//默认隐藏
                            } else {
                                preValue[key] = model;
                                model[key + "rowspan"] = 1;
                            }
                        }
                    }
                }
                preValue = null;
            }

            //总计清空
            if (totalOpt) {
                for (var key in totalOpt.fields)
                    totalOpt.fields[key] = 0;
            }

            //添加数据
            var cols = dataCache.cols[that.tableIndex], trsFixedL = [], trsFixedR = [], noChecked = true;
            //遍历数据
            $(data).each(function (a, b) {
                var trs = [], trsFixedLOne = [], trsFixedROne = [];
                //添加数据前
                typeof options.onBeforeAddRow === "function" && options.onBeforeAddRow(a, b);
                trs.push('<tr data-index=' + a + '>');
                //折叠行
                if (options.expandRow) {
                    trs.push('<td><span class="raytable-expand"></span></td>');
                }
                //遍历行
                $.each(cols, function (c, opt) {
                    var td = [],
                        field = opt.field,
                        cellCss = 'raytable-cell-' + that.tableIndex + '-' + field,
                        cellDataCss = 'raytable-cell-data-' + that.tableIndex + '-' + field,
                        rowspan = b[field + "rowspan"];

                    td.push('<td data-field="' + field + '"');
                    if (rowspan !== undef && rowspan > 1)
                        td.push(' rowspan=' + rowspan);
                    td.push(' class="' + cellCss);
                    td.push(opt.hidden ? ' hidden' : '');
                    td.push(options.nowrap ? ' raytable-nowrap' : ' ' + cellDataCss);
                    if (rowspan !== undef && rowspan === -1)
                        td.push(' hiddenImp');
                    td.push('"');//end class
                    td.push(opt.islink ? ' islink' : '');
                    td.push('>');

                    var value, formatIsFunc = typeof opt.formatter === "function";
                    if (field === 'chk') {
                        //checkbox
                        var title;
                        formatIsFunc && (title = opt.formatter(b[field], b, a));
                        value = ['<input type="checkbox" class="rayui-checkbox ',
                            chkClass,
                            '"',//end class
                            title ? ' ray-title="' + title + '"' : "",
                            ' ray-event="' + chkOneEvt + '" ',
                            b.hasOwnProperty(options.fieldChecked) && b[options.fieldChecked] ? function () {
                                if (!options.singleSelect || options.singleSelect && noChecked) {
                                    noChecked = false;
                                    return "checked ";
                                }
                                return " ";
                            }() : "",
                            b.hasOwnProperty(options.fieldDisableCheck) && b[options.fieldDisableCheck] ? "disabled " : "",
                            (options.chkSkin ? 'skin="' + options.chkSkin + '"' : ""),
                            '/>'].join('');
                    } else if (field === "rowNumbers") {
                        value = a + 1;
                    } else if (opt.template) {
                        value = tmpl.render(opt.template, b);
                    } else if (formatIsFunc) {
                        //formatter函数
                        value = opt.formatter(b[field], b, a);
                        //模板
                    } else {
                        value = b[field];
                        if (opt.dataType === "html" && typeof value === "string")
                            value = value.replace(/[<>&"]/g, function (c) { return { '<': '&lt;', '>': '&gt;', '&': '&amp;', '"': '&quot;' }[c]; });
                    }
                    if (value === undef || value === null || value === '') value = "&nbsp;";

                    td.push(options.nowrap ? '<div class="raytable-nowrap ' + cellCss + ' ' + cellDataCss + '">' + value + '</div>' : value);
                    td.push('</td>');

                    var strTmp = td.join('');
                    trs.push(strTmp);

                    opt.fixed === 'left' && (trsFixedLOne.push(strTmp));
                    opt.fixed === 'right' && (trsFixedROne.push(strTmp));
                });

                trs.push("</tr>");
                var strHtml = trs.join('');
                var $tr = $("" + strHtml);
                $tr.appendTo($tbody);
                //首次复制数据设置行高度
                if (trsFixedLOne.length > 0) {
                    trsFixedL.push('<tr data-index=' + a + '>' + trsFixedLOne.join('') + "</tr>");
                    trsFixedLOne = [];
                }
                if (trsFixedROne.length > 0) {
                    trsFixedR.push('<tr data-index=' + a + '>' + trsFixedROne.join('') + "</tr>");
                    trsFixedROne = [];
                }
                //添加数据后
                typeof options.onAddRow === "function" && options.onAddRow(a, b, $tr);
            });
            data = null;
            //添加固定列数据
            if (trsFixedL.length > 0) {
                $fixedtbodyl.html(trsFixedL.join(''));
            }
            if (trsFixedR.length > 0) {
                $fixedtbodyr.html(trsFixedR.join(''));
            }

            DealClass.utils.renderTotalData.call(that);
        },
        renderTotalData: function () {
            var that = this,
                jqobjs = dataCache.jqobjs[that.tableIndex],
                options = that.options,
                totalOpt = options.totalRow;

            //总计清空
            if (!totalOpt) return;

            for (var key in totalOpt.fields)
                totalOpt.fields[key] = 0;

            var cols = dataCache.cols[that.tableIndex],
                data = DealClass.utils.getData.call(that);

            var tfoot = [];
            tfoot.push('<tr>');

            //折叠行
            if (options.expandRow) {
                tfoot.push('<td><span class="raytable-expand"></span></td>');
            }

            // (options.totalRow = { field: 0, text: '总计', fields: {} });
            var isFunc = typeof options.totalRowFunc === "function";
            //遍历数据
            $(data).each(function (a, b) {
                for (var key in totalOpt.fields) {
                    if (isFunc)
                        totalOpt.fields[key] = options.totalRowFunc(totalOpt.fields[key], b[key], key);
                    else
                        totalOpt.fields[key] += b[key];
                }
            });
            //遍历行
            $.each(cols, function (c, opt) {
                if (opt.hidden) return true;
                var td = [], field = opt.field,
                    cellCss = 'raytable-cell-' + that.tableIndex + '-' + field,
                    cellDataCss = 'raytable-cell-data-' + that.tableIndex + '-' + field;

                var value = totalOpt.field === c || totalOpt.field === field ? totalOpt.text : totalOpt.fields[field] || "";

                td.push('<td data-field="' + field + '"');
                td.push(' class="' + cellCss);
                td.push(opt.hidden ? ' hidden' : '');
                td.push(options.nowrap ? ' raytable-nowrap' : ' ' + cellDataCss);
                td.push('"');//end class
                td.push('>');
                td.push(options.nowrap ? '<div class="raytable-nowrap ' + cellCss + ' ' + cellDataCss + '">' + value + '</div>' : value);
                td.push('</td>');
                tfoot.push(td.join(''));
            });
            tfoot.push('</tr>');

            jqobjs.tb_total.html(tfoot.join(''));
        },
        setFixedRowHeight: function () {
            var that = this,
                jqobjs = dataCache.jqobjs[that.tableIndex],
                $tbody = jqobjs.tb_body.find(">tbody"),
                $fixedtbodyl = jqobjs.tb_fixed_l.find("div.raytable-body-noscroll table>tbody>tr"),
                $fixedtbodyr = jqobjs.tb_fixed_r.find("div.raytable-body-noscroll table>tbody>tr");

            $tbody.find("tr").each(function (a) {
                var height = $(this).height();
                $fixedtbodyl.eq(a).height(height);
                $fixedtbodyr.eq(a).height(height);
            });
        },
        initHeight: function () {
            var that = this,
                $t = $(this.elem),
                options = that.options,
                jqobjs = dataCache.jqobjs[that.tableIndex],
                $theaddiv = jqobjs.tb_head_box,
                $tpagediv = jqobjs.tb_page_box,
                $tbodydiv = jqobjs.tb_body_box,
                fullHeightGap;

            !options.heightSetting && (options.heightSetting = options.height);

            if (/^full-\d+$/.test(options.heightSetting)) {//full-差距值
                fullHeightGap = options.heightSetting.split('-')[1];
                options.height = $win.height() - fullHeightGap;
            } else if (/^top-\d+$/.test(options.heightSetting)) {//top-差距值
                fullHeightGap = $t.offset().top;
                fullHeightGap += parseInt(options.heightSetting.split('-')[1]);
                options.height = $win.height() - fullHeightGap;
            } else if (/^sel-[#|\.][\w]+-\d+$/.test(options.heightSetting)) { //sel-id序列-差距值
                fullHeightGap = $t.offset().top;
                var list = options.heightSetting.split('-');
                $("" + list[1]).each(function () {
                    fullHeightGap += $(this).outerHeight();
                });
                if (list.length === 3) fullHeightGap += parseInt(list[2]);
                options.height = $win.height() - fullHeightGap;
            }

            //最终高度不能小于最小高度
            if (options.height < options.minHeight) options.height = options.minHeight;
            //数据高度-head-page-2px(raytable-box上下各1px border)
            var tmpH = options.height - $theaddiv.outerHeight() - $tpagediv.outerHeight() - jqobjs.tb_total_boxmain.outerHeight() - 2;
            $tbodydiv.outerHeight(tmpH);//数据表格设置高度
        },
        fullHeight: function () {
            //计算高
            var that = this,
                options = that.options;

            var jqobjs = dataCache.jqobjs[that.tableIndex],
                $theaddiv = jqobjs.tb_head_box,
                $tbodydiv = jqobjs.tb_body_box;

            //如果设置的是固定高度，则无需再设置了，ajax时initHeight方法会调用两遍
            if (!/^\d+$/.test(options.heightSetting)) DealClass.utils.initHeight.call(that);
            var tbodydiv = $tbodydiv[0];
            if (tbodydiv.scrollHeight > tbodydiv.clientHeight) {
                //说明有竖向滚动条
                $theaddiv.css("margin-right", (scrollGap.width) + "px");
                jqobjs.tb_total_box.css("margin-right", (scrollGap.width) + "px");
                //右侧固定和数据最右侧列还原右边框
                jqobjs.tb_fixed_r.find("tr>td:last,th:last").removeClass("last");
                jqobjs.tb_fixed_r.css("right", scrollGap.width + "px");
            } else {
                $theaddiv.css("margin-right", "0");
                jqobjs.tb_total_box.css("margin-right", "0");
                //右侧固定和数据最右侧列移除右边框
                jqobjs.tb_fixed_r.find("tr").each(function () {
                    $(this).find("td:last,th:last").addClass("last");
                });
                jqobjs.tb_fixed_r.css("right", "0");
            }

        },
        //自适应宽度以数据宽度为准
        fullWidth: function () {
            var that = this,
                options = that.options,
                jqobjs = dataCache.jqobjs[that.tableIndex],
                $tbDataFirstTr = jqobjs.tb_body.find("tr:first"),
                $tbodydiv = jqobjs.tb_body_box,
                tbodydiv = $tbodydiv[0];

            //百分比宽度
            if (options.isPercentWidth && !options.resized) {
                var cols = dataCache.cols[that.tableIndex],
                    totalWidth = jqobjs.tb_head_box.width() - cols.length,
                    surplus = totalWidth, fieldStartCss;
                $.each(cols, function (c, opt) {
                    var field = opt.field,
                        cellClass = '.raytable-cell-' + that.tableIndex + '-' + field,
                        cellCss = DealClass.utils.getCssStyle.call(that, cellClass);
                    if (opt.width === "*") {
                        fieldStartCss = cellCss;
                        return true;
                    }
                    var percent = ("" + opt.width).replace("%", ""),
                        width = totalWidth / 100 * (parseFloat(percent));

                    width = Math.floor(width);//解决那零点几导致的横向滚动条
                    cellCss.style.width = width + "px";
                    if (width < options.cellMinWidth) cellCss.style["min-width"] = width + "px";
                    surplus -= width;
                    return true;
                });
                if (fieldStartCss) {
                    fieldStartCss.style.width = surplus + "px";
                    if (surplus < options.cellMinWidth) fieldStartCss.style["min-width"] = surplus + "px";
                }
            }

            //有自适应列时动态修改表头宽度
            if (options.autoCols && !options.resized) {
                var field, w;
                //必须，为了自适应数据宽度
                for (field in options.autoCols) {
                    options.autoCols[field].style.style.width = "";
                }

                //如果table小于div宽度就100%
                tbodydiv.clientWidth > options.minWidth && (jqobjs.tb_head_body.css("width", "100%"));
                if (!options.nowrap) {
                    //允许换行，使用table的自适应宽度
                    for (field in options.autoCols) {
                        //需要减去右边框1px，否则总是出现横向滚动条，不要使用width函数
                        w = $tbDataFirstTr.find("td[data-field=" + field + "]").outerWidth();
                        options.autoCols[field].style.style.width = w - 1 + "px";
                    }
                } else {
                    //不允许换行
                    var obj, aver = 0;
                    if (tbodydiv.clientWidth > options.minWidth) {
                        var widthGap = tbodydiv.clientWidth - options.minWidth;
                        aver = Math.floor(widthGap / options.autoColNums);
                    }
                    for (field in options.autoCols) {
                        obj = options.autoCols[field];
                        obj.style.style.width = obj.minWidth + aver + "px";
                    }
                }
                //修正头部滚动条
                jqobjs.tb_head_box.scrollLeft($tbodydiv.scrollLeft());
            }

            //修改div宽度隐藏固定列滚动条
            var clientH = Math.min(tbodydiv.clientHeight, jqobjs.tb_body.height()),//取bodydiv和table的最小高度
                $tbodyFixedBoxNoscroll = jqobjs.tb_box.find("div.raytable-fixed .raytable-body-noscroll");
            $tbodyFixedBoxNoscroll.each(function () {
                var innerTablediv = $(this).find(">.raytable-body-box"),
                    tbodyWidth = innerTablediv.find(".raytable-body").width();
                innerTablediv.outerHeight(clientH).outerWidth(tbodyWidth + scrollGap.width);
                $(this).outerWidth(tbodyWidth);
            });

            //判断是否去掉最后一列边框，数据宽度大于数据box可视宽度时去掉右边框
            var dataWidth = $tbodydiv.find(".raytable-body").outerWidth();
            if (dataWidth < tbodydiv.clientWidth) {
                jqobjs.tb_body.find("tr>td.last").removeClass("last");
                jqobjs.tb_head.find("tr>th.last").removeClass("last");
                jqobjs.tb_total.find("tr>td:last").removeClass("last");
            } else {
                jqobjs.tb_body.find("tr").each(function () {
                    $(this).find("td:last").addClass("last");
                });
                jqobjs.tb_head.find("tr").each(function () {
                    $(this).find("th:last").addClass("last");
                });
                jqobjs.tb_total.find("tr>td:last").addClass("last");
            }

            /*判断显隐补丁
                        -------     有横向    无横向  正好无横向
                        有竖向       显示       隐藏        显示
                        无竖向       隐藏       隐藏        隐藏
                 正好无竖向       隐藏       隐藏        隐藏
            */
            if (dataWidth >= tbodydiv.clientWidth && tbodydiv.scrollHeight > tbodydiv.clientHeight) {
                //显示
                jqobjs.tb_amend.removeClass("hidden");
            } else {
                //隐藏
                jqobjs.tb_amend.addClass("hidden");
            }
        },
        modifyFixedHeight: function (resizeHead) {
            var that = this,
                jqobjs = dataCache.jqobjs[that.tableIndex],
                tbodyBox = jqobjs.tb_body_box[0],
                $fixedR = jqobjs.tb_fixed_r,
                options = that.options;

            //修改复制数据的高度，数据不自动换行时不需要调整
            if (!options.nowrap) {
                //不管本地数据还是ajax数据
                var $tbody = jqobjs.tb_body.find(">tbody"),
                    bodyFixed = jqobjs.tb_fixed.find(".raytable-body-box>table");

                if (bodyFixed.length > 0) {
                    $tbody.find("tr").each(function (a) {
                        bodyFixed.find("tr:eq(" + a + ")").outerHeight($(this).outerHeight());
                    });
                }
            }

            //修改amend的高度
            DealClass.utils.setAmendHeight.call(that);

            //有自动列宽时，或则拖拽时（由拖拽自己判断），动态修改固定列表头行高
            if (resizeHead || options.autoColNums > 0) {
                //修改表头高度，如果设置表头宽度合理一般不用修改，设置不合理也不好看
                //注意多行固定问题，倒着修改正好
                var headFixedL = jqobjs.tb_fixed_l.find(".raytable-head"),
                    headFixedR = jqobjs.tb_fixed_r.find(".raytable-head"),
                    head = jqobjs.tb_head,
                    trheadCount = head.find("tr").length;

                var trc = headFixedL.find("tr").length, tmp, index;
                if (trc > 0) {
                    tmp = trheadCount - 1; index = trc - 1;
                    while (index >= 0) {
                        headFixedL.find("tr:eq(" + (index--) + ")").height(head.find("tr:eq(" + (tmp--) + ")").height());
                    }
                }
                trc = headFixedR.find("tr").length;
                if (trc > 0) {
                    tmp = trheadCount - 1; index = trc - 1;
                    var trh = 0, datatrH;
                    while (index >= 0) {
                        datatrH = head.find("tr:eq(" + (tmp--) + ")").height();
                        trh += datatrH;
                        headFixedR.find("tr:eq(" + (index--) + ")").height(datatrH);
                    }
                }
            }//end if

            //判断是否隐藏右侧固定列
            if ($fixedR.children().length > 0) {
                if (tbodyBox.scrollWidth > tbodyBox.clientWidth) {
                    //有横向滚动条，有滚动条事件所以不能隐藏（隐藏后滚动无效），这里只能使用飘出
                    $fixedR.removeClass("blowout-right");
                } else {
                    $fixedR.addClass("blowout-right");
                }
            }
        },
        getPageData: function () {
            var that = this,
                page = that.options.page,
                data = dataCache.datas[that.tableIndex],
                onePageData = [];

            var count = data.length, start = 0, end = data.length;
            if (page) {
                start = page.curr === 1 ? 0 : (page.curr - 1) * page.limit;
                end = page.curr * page.limit;
            }

            while (start < end) {
                if (start >= count) break;
                onePageData.push(data[start++]);
            }
            return onePageData;
        },
        initPage: function () {
            var that = this,
                jqobjs = dataCache.jqobjs[that.tableIndex],
                options = that.options,
                page = options.page;
            if (!page) return;

            var data = dataCache.datas[that.tableIndex];
            if (!options.url && page.count === -1) page.count = data.length;

            page.elem = jqobjs.tb_page_box.html("");
            options.pageHandle = pagePg.render(page);
            options.page = options.pageHandle.options;//统一参数

            //page分页select
            options.pageHandle.on("limitChanged", function (old, to) {
                DealClass.utils.reload.call(that);
                options.onPageLimitChanged && options.onPageLimitChanged(old, to);
            });
            //page页面跳转
            options.pageHandle.on("jump", function (old, to) {
                DealClass.utils.reload.call(that);
                options.onPageJump && options.onPageJump(old, to);
            });

        },
        clearData: function () {
            var that = this,
                jqobjs = dataCache.jqobjs[that.tableIndex],
                $tbody = jqobjs.tb_body.find(">tbody"),
                $fixedtbodyl = jqobjs.tb_fixed_l.find("div.raytable-body-noscroll table>tbody"),
                $fixedtbodyr = jqobjs.tb_fixed_r.find("div.raytable-body-noscroll table>tbody");

            $tbody.html("");
            $fixedtbodyl.html("");
            $fixedtbodyr.html("");
            jqobjs.tb_fixed_l.find(".raytable-body-box").css("height", "");
            jqobjs.tb_fixed_r.find(".raytable-body-box").css("height", "");
        },
        deleteData: function (data) {
            var that = this,
                options = that.options,
                key = options.fieldSerial,
                iskey = key !== undef,
                datas = dataCache.datas[that.tableIndex],
                start, end, count, dataStr;

            if (options.url || !options.page) {
                //ajax
                start = 0;
                end = datas.length;
                count = datas.length;
            } else {
                //本地
                var page = options.page;
                start = page.curr === 1 ? 0 : (page.curr - 1) * page.limit;
                end = page.curr * page.limit;
                count = datas.length;
            }

            if (iskey && datas[0].hasOwnProperty(key)) {
                while (start < end) {
                    if (start >= count) break;
                    if (datas[start][key] === data[key]) {
                        datas.splice(start, 1);
                        return;
                    }
                    start++;
                }
            } else {
                dataStr = JSON.stringify(data);
                while (start < end) {
                    if (start >= count) break;
                    if (JSON.stringify(datas[start]) === dataStr) {
                        datas.splice(start, 1);
                        return;
                    }
                    start++;
                }
            }
        },
        reload: function (option) {
            option !== undef && $.extend(true, this.options, option);
            var that = this,
                options = that.options;

            if (options.url) {
                DealClass.utils.ajaxData.call(that);
            } else {
                DealClass.utils.onRecvData.call(that);
            }
        },
        getCssStyle: function (css) {
            var that = this,
                jqobjs = dataCache.jqobjs[that.tableIndex],
                style = jqobjs.div_style.find("style")[0],
                sheet = style.sheet || style.styleSheet,
                rules = sheet.cssRules || sheet.rules;

            var curCss;
            $(rules).each(function (a, rr) {
                if (css === rr.selectorText) {
                    curCss = rr;
                    return false;
                }
                return true;
            });
            //如果没有则添加一条，因为初始化的时候保证一定含有，所以这里没必要再添加了
            return curCss;
        },
        getData: function (index) {
            var that = this,
                options = that.options,
                datas = options.url ? dataCache.datas[that.tableIndex] : DealClass.utils.getPageData.call(that);

            //如果开启本地排序则数据排序
            if (datas.length > 1 && options.initSort && options.localSort)
                datas.raysort(options.initSort.sortField, options.initSort.sortType === 'desc');

            return index >= 0 ? datas[index] : datas;
        },
        checkIsAll: function () {
            var that = this,
                options = that.options;

            if (options.singleSelect) return;

            var jqobjs = dataCache.jqobjs[that.tableIndex];
            var $allchk = jqobjs.tb_box.find(".raytable-head input." + chkClass),
                nochkedLen = jqobjs.tb_body_box.find("input." + chkClass).not(":checked").length;
            $allchk.prop("checked", nochkedLen === 0);
            chkpg[nochkedLen === 0 ? "check" : "unCheck"]($allchk);
        },
        addEvents: function () {
            var that = this,
                dict = {},
                $doc = $(doc),
                $body = $('body'),
                jqobjs = dataCache.jqobjs[that.tableIndex],
                $thisAllTable = jqobjs.tb_head_body,
                $tbodydiv = jqobjs.tb_box.find("div.raytable-body-box"),
                options = that.options,
                isresizing = false;

            //拖拽调整宽度
            jqobjs.tb_box.find(".raytable-head").on('mousemove.' + plugName, "th[class*=raytable-cell-resize]", function (e) {
                if (dict.resizeStart) return;
                var othis = $(this),
                    oLeft = othis.offset().left,
                    pLeft = e.pageX - oLeft;
                //是否处于拖拽允许区域
                dict.allowResize = othis.outerWidth() - pLeft <= 10;
                $body.css('cursor', (dict.allowResize ? 'col-resize' : ''));
            }).on('mouseleave.' + plugName, "th[class*=raytable-cell-resize]", function () {
                if (dict.resizeStart) return;
                $body.css('cursor', '');
            }).on('mousedown.' + plugName, "th[class*=raytable-cell-resize]", function (e) {
                if (dict.allowResize) {
                    e.preventDefault();
                    var $othis = $(this);
                    dict.elem = this;
                    dict.width = $othis.width();
                    dict.resizeStart = true; //开始拖拽

                    var thcss = ".raytable-cell-" + that.tableIndex + "-" + $(dict.elem).data("field");
                    dict.cssRule = DealClass.utils.getCssStyle.call(that, thcss);

                    var cssminWidth = parseFloat($othis.css("min-width").replace("px", ""));
                    dict.minWidth = cssminWidth === 0 ? options.cellMinWidth : cssminWidth;
                    dict.offset = e.clientX; //记录初始坐标
                    var tbone = $thisAllTable.eq(0);
                    //记录当前table宽度
                    dict.tb_width = tbone.outerWidth();
                    dict.tb_minwidth = parseFloat(tbone.css("min-width").replace("px", ""));
                }
            });

            //拖拽中
            $doc.on('mousemove.' + plugName, function (e) {
                if (dict.resizeStart) {
                    e.preventDefault();
                    if (dict.elem) {
                        options.resized = true;
                        var gap = e.clientX - dict.offset;
                        var setWidth = dict.width + gap;
                        if (setWidth > dict.minWidth) {
                            dict.cssRule.style.width = setWidth + "px";
                            var newTbW = dict.tb_width + gap;
                            //修改最小宽度和宽度
                            $thisAllTable.outerWidth(newTbW);
                            if (newTbW < dict.tb_minwidth)
                                $thisAllTable.css("min-width", newTbW + "px");
                            //修改固定数据的高度
                            DealClass.utils.fullWidth.call(that);
                            //修改固定数据的高度
                            DealClass.utils.modifyFixedHeight.call(that, true);
                        }
                    }
                    isresizing = true;
                }
            }).on('mouseup.' + plugName, function () {
                if (dict.resizeStart) {
                    dict = {};
                    $body.css('cursor', '');
                }
            });

            //行事件
            var $tables = jqobjs.tb_box.find("div.raytable-body-box>table");
            if ($tables.length > 1) {
                $tables.on("mouseenter." + plugName, "tr", function () {
                    $tables.find("tr:eq(" + $(this).index() + ")").addClass("raytable-tr-hover");
                }).on("mouseleave." + plugName, "tr", function () {
                    $tables.find("tr:eq(" + $(this).index() + ")").removeClass("raytable-tr-hover");
                });
            }

            //横竖向滚动条，$tbodydiv有3个，数据、左固定、右固定
            var funcScrollTop = function () {
                if ($(this).attr("scroll-left") === "1") {
                    var tmp = $(this).scrollLeft();
                    jqobjs.tb_head_box.scrollLeft(tmp);
                    jqobjs.tb_total_box.scrollLeft(tmp);
                }
                $tbodydiv.not(this).scrollTop($(this).scrollTop());
            }
            $tbodydiv.on("scroll." + plugName, funcScrollTop);
            $tbodydiv.hover(function () {
                $tbodydiv.not(this).off("scroll." + plugName, funcScrollTop);
            }, function () {
                //$tbodydiv.not(this).on("scroll.raytable", funcScrollTop);
                //不能使用上面代码，因为当删除数据导致div没有时，数据的div无法绑定时间
                $tbodydiv.off("scroll." + plugName, funcScrollTop)
                    .on("scroll." + plugName, funcScrollTop);
            });

            //checkbox
            var tmpLength = jqobjs.tb_fixed_l.find(".raytable-head-box").length,
                $lefttb = tmpLength > 0 ? jqobjs.tb_fixed_l : jqobjs.tb_box;
            chkpg.on("check", function (obj) {
                obj.e.stopPropagation();
                //obj包含：event: all|row, elem, checked
                var evt = obj.event, value = obj.checked, objChk;

                //全选
                if (evt === chkAllEvt) {
                    var allChk = jqobjs.tb_box.find("input." + chkClass).prop("checked", value);
                    chkpg[value ? "check" : "unCheck"](allChk);

                    //回调事件
                    objChk = {
                        type: "all",
                        index: -1,
                        checked: value,
                        data: DealClass.utils.getData.call(that)
                    };
                    typeof options.onCheck === "function" && (options.onCheck.call(this, objChk));
                    return;
                }

                var $tr = $(this).closest("tr"), index = $tr.index(),
                    $chkedInput = $lefttb.find("input." + chkClass + ":checked");
                //单选
                if (options.singleSelect && $chkedInput.length > 1) {
                    chkpg.click($chkedInput.not($(obj.elem)));
                }

                //同步数据表格当前行选中
                tmpLength > 0 && (chkpg[value ? "check" : "unCheck"](jqobjs.tb_body_box.find(".raytable-body tr:eq(" + index + ") input." + chkClass).prop("checked", value)));

                //如果是允许多选，需要判断all是否选中
                DealClass.utils.checkIsAll.call(that);

                //回调事件
                objChk = {
                    type: "one",
                    index: index,
                    checked: value,
                    data: DealClass.utils.getData.call(that, index)
                };

                typeof options.onCheck === "function" && (options.onCheck.call(this, objChk));
            }, jqobjs.tb_box);

            //排序
            var sortThs = jqobjs.tb_box.find("th.raytable-sort-th");
            jqobjs.tb_box.on("click.sort." + plugName, "th.raytable-sort-th,span.raytable-sort-span>i", function (e) {
                e.stopPropagation();
                if (isresizing) {
                    isresizing = false;
                    return;
                }
                //如果没有data-field，说明点击的是i
                var tosortfield, tosorttype, $th;
                if (this.tagName === "I") {
                    $th = $(this).closest("th");
                    tosortfield = $th.data("field");
                    tosorttype = $(this).prop("class").indexOf("asc") > -1 ? "asc" : "desc";
                } else {
                    $th = $(this);
                    var nowSortType = $(this).attr("sort-type");
                    tosortfield = $(this).data("field");
                    tosorttype = nowSortType === undef ? "asc" : nowSortType === "asc" ? "desc" : "asc";
                }
                sortThs.attr("sort-type", "");
                $th.attr("sort-type", tosorttype);

                !options.initSort && (options.initSort = {});
                options.initSort.sortField = tosortfield;
                options.initSort.sortType = tosorttype;

                typeof options.onSort === "function" && options.onSort(options.initSort);

                DealClass.utils.reload.call(that);
            });

            //单元格显示更多按钮，如果出现省略，则可查看更多
            var tds = 'td.raytable-nowrap:not("[class*=opt]"):not("[islink]")';
            jqobjs.tb_box.on("mouseenter.cellshow." + plugName, tds, function () {
                var obj = $(this).find("div")[0];
                if (obj.scrollWidth > $(obj).outerWidth()) {
                    $('<div class="rayui-table-td-detail"><i class="ra ra-single-angle-down"></i></div>').appendTo($(this));
                }
            }).on("mouseleave.cellshow." + plugName, tds, function () {
                $(this).find(".rayui-table-td-detail").remove();
            }).on("click." + plugName, '.rayui-table-td-detail', function (e) {
                e.stopPropagation();
                var obj = $(this).siblings("div")[0];
                var $p = $(".raytable-tips");
                if ($p.length === 0) {
                    $p = $('<div class="raytable-tips"><div class="raytable-tips-content"></div></div>').appendTo($body);
                    $('<i class="raytable-tips-close"></i>')
                        .appendTo($p)
                        .click(function () {
                            $p.remove();
                        });
                }
                var $content = $p.find(".raytable-tips-content");
                $content.html($(obj).html());

                //计算left、top
                var cwidth = $win.width(),
                    offset = $(obj).closest("td").offset(),
                    left, top = offset.top - 1,
                    width = $p.outerWidth();

                width > 500 && (width = 500);
                if (offset.left + width < cwidth) {
                    left = offset.left;
                } else {
                    var tmpW = offset.left + $(obj).outerWidth();
                    if (width > tmpW)
                        width = tmpW;
                    left = tmpW - width;
                }

                $p.css({
                    width: width + "px",
                    top: top + "px",
                    left: left + "px"
                });
            });

            //点击行
            jqobjs.tb_box.on("click." + plugName, ".raytable-body tr", function () {
                var index = $(this).data("index");
                if (options.rowSelectStyle) {
                    if (options.singleSelect)
                        $tables.find("tr." + options.rowSelectStyle).removeClass(options.rowSelectStyle);
                    $tables.find("tr[data-index=" + index + "]").toggleClass(options.rowSelectStyle);
                }
                if (options.checkOnRowClick) {
                    var $iobj = $lefttb.find("tr[data-index=" + index + "] ." + chkClass + ":enabled");
                    $iobj.length > 0 && chkpg.click($iobj);
                }
            });
        },
        on: function (event, func) {
            if (typeof event !== "string" || typeof func !== "function") return;
            var that = this,
                options = that.options,
                jqobjs = dataCache.jqobjs[that.tableIndex],
                $tbody = jqobjs.tb_body;

            switch (event) {
                //按钮点击事件
                case "click":
                    jqobjs.tb_box.on("click.btn." + plugName, ".raytable-body td[data-field^=opt] *[ray-event]", function (e) {
                        var evt = $(this).attr("ray-event"),
                            $tr = $(this).closest("tr"),
                            index = $tr.data("index"),
                            datas = DealClass.utils.getData.call(that);

                        var data = datas[index],
                            $datatr = {
                                e: e,
                                index: index,
                                data: data,
                                tr: $tbody.find("tr[data-index=" + index + "]"),
                                del: function () {
                                    //删除本地数据
                                    DealClass.utils.deleteData.call(that, data);
                                    //修改页码总数
                                    options.page && (options.page.count -= 1);
                                    //本地重新渲染数据
                                    DealClass.utils.onRecvData.call(that);
                                },
                                update: function () {
                                    //本地重新渲染数据
                                    DealClass.utils.onRecvData.call(that);
                                }
                            };
                        func.call(this, evt, $datatr);
                    });
                    break;
                //swich点击事件
                case "swich":
                    rayui.swich && rayui.swich.on("swich", function (obj) {
                        //this为渲染的swich，obj包含： event,elem,value,title
                        var $tr = $(this).closest("tr"),
                            index = $tr.data("index"),
                            data = DealClass.utils.getData.call(that, index),
                            $datatr = {
                                index: index,
                                data: data,
                                tr: $tbody.find("tr[data-index=" + index + "]")
                            };
                        $datatr = $.extend($datatr, obj);
                        return func.call(this, obj.event, $datatr);
                    }, jqobjs.tb_box);
                    break;
                //展开行
                case "expand":
                    jqobjs.tb_box.on("click.expand." + plugName, "td>.raytable-expand", function (e) {
                        e.stopPropagation();
                        var $trp = $(this).closest("tr"),
                            expand = $trp.attr("expand");
                        if (expand !== undef) {
                            var $tr = $trp.next("tr");
                            if (expand === "1") {
                                $tr.hide();
                                $trp.attr("expand", "0");
                            } else {
                                $tr.show();
                                $trp.attr("expand", "1");
                            }
                            return;
                        }

                        var index = $trp.data("index"),
                            datas = DealClass.utils.getData.call(that),
                            data = datas[index],
                            $trAppend = $([
                                '<tr>',
                                '<td><span class="raytable-expand"></span></td>',
                                '<td colspan="' + options.colsCount + '">',
                                '<div class="raytable-expand-box">',
                                '</div>',
                                '</td>',
                                '</tr>'
                            ].join(''));

                        $trp.attr("expand", "1").after($trAppend);

                        var $container = $trAppend.find(".raytable-expand-box"),
                            str = func.call(this, index, data, $container);
                        str != null && $container.append(str);
                    });
                    break;
                //以下事件写相应属性事件也是可以的
                //排序
                case "sort": options.onSort = func; break;
                //选中
                case "check": options.onCheck = func; break;
            }
        }
    }

    DealClass.prototype = {
        on: function (event, callback) {
            DealClass.utils.on.call(this, event, callback);
            return this;
        },
        reload: function (option) {
            DealClass.utils.reload.call(this, option);
            return this;
        },
        getSelectedRows: function () {
            var list = [],
                that = this,
                jqobjs = dataCache.jqobjs[that.tableIndex],
                $tbody = jqobjs.tb_body,
                datas = DealClass.utils.getData.call(that);

            $tbody.find("input." + chkClass).each(function (a) {
                if (this.checked) {
                    list.push({
                        index: a,
                        data: datas[a]
                    });
                }
            });
            return list;
        },
        getData: function () {
            return DealClass.utils.getData.call(this);
        },
        getDataByIndex: function (index) {
            if (index === -1) return [];
            return DealClass.utils.getData.call(this, index);
        }
    };

    var table = {
        options: DealClass.option,
        render: function (option) {
            scrollGap.width || function () {
                //可以在这里加载css
                DealClass.utils.initDefault();
            }();
            var obj = option.elem;
            if ($(obj).length === 0) return "DOM对象不存在";
            var classObj = new DealClass(obj, option);
            dataCache.tables[tableindex++] = classObj;
            return classObj;
        }
    }

    exports("table", table);
}, rayui.jsAsync());
